// Include files.
#include <cstddef>
#include "../Internal/FpkException.hpp"
#include "../Internal/NullDeleter.hpp"
#include "../SystematicRobot.hpp"
#include "Service.hpp"

/**
 *  Constructor for Service.
 */
Service::Service() :
	m_isStarted(false)
{
}

/**
 *  Destructor for Service.
 */
Service::~Service()
{
}

/**
 *  Get whether the Service is started.
 *  
 *  @return Whether the Service is started.
 */
bool Service::GetIsStarted() const
{
	return m_isStarted;
}

/**
 *  Starts the Service and subscribes to the robot.
 */
void Service::Start()
{
	if (!m_isStarted)
	{	
		if (m_robot == NULL)
			throw FpkException("Can not start a service when not added to a robot.");
		
		if (m_parent != NULL)
		{
			// Service has a parent service (probably a service, might be some other kind of subscriber if we screwed up).
			
			if (!(m_parent->m_isSubscribed))
				throw FpkException("Can not start a service when it's parent is not started.");
		}
		
		AquireLocks();
		SetIsSubscribed(true);
		m_isStarted = true;
		HandleStart();
	}
}

/**
 *  Stops the Service and unsubscribes from the robot.
 */
void Service::Stop()
{
	{
		// Stop each service.
		
		set<Service*>::iterator it;
				
		for (it = m_subservices.begin(); it != m_subservices.end(); ++it)
		{
			// Stop subservice.
			(*it)->Stop();
		}
	}
	
	ReleaseLocks();
	
	HandleStop();
	m_isStarted = false;
	SetIsSubscribed(false);
}

/**
 *  Add a subservice to the service.
 *  
 *  This is necessary for two reasons.
 *    1. So subservice gets added to the robot automatically.
 *    2. So this service and one subservice can share a control lock on the same object (such as a subsystem).
 *  
 *  @param serivice A reference to the Service to be added as a subservice.
 *  
 *  @returns The service parameter.
 */
Service &Service::AddSubservice(Service &service)
{
	// Add service as child subscriber.
	AddChild(service);
	
	// Add service as subservice.
	m_subservices.insert(&service);
	
	return service;
}

/**
 *  This function should be overridden to handle the Service starting.
 */
void Service::HandleStart()
{
}

/**
 *  This function should be overridden to handle the Service stopping.
 */
void Service::HandleStop()
{
}

/**
 *  This function should be overridden to handle the periodic Service tasks.
 *  It will be called periodically when the this controller is started.
 */
void Service::HandlePeriodic()
{
}
